package sample.com.imagecompress.mamera.activity;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.widget.ImageButton;

import java.io.File;
import java.io.FileOutputStream;
import java.util.List;

import sample.com.imagecompress.R;

public class MameraActivity extends AppCompatActivity {

    private static final String TAG = MameraActivity.class.getSimpleName();
    public static final String EXTRA_FILE_PATH = "PHOTO_FILE_PATH";

    private Camera camera;
    private SurfaceHolder surfaceHolder;

    private SurfaceView surfaceView;
    private ImageButton btn_capture, btn_back, btn_flashlight;

    private int cameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
    private Camera.Parameters cameraParameters;

    private int screenWidth, screenHeight;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        // 全屏显示
        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN |
                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

        if (Build.VERSION.SDK_INT >= 21) {
            View view = getWindow().getDecorView();
            view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        setContentView(R.layout.activity_mamera);
        initView();

        // 透明状态栏
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }

        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            WindowMetrics currentWindowMetrics = wm.getCurrentWindowMetrics();
            screenWidth = currentWindowMetrics.getBounds().width();
            screenHeight = currentWindowMetrics.getBounds().height();
        } else {
            DisplayMetrics metrics = new DisplayMetrics();
            wm.getDefaultDisplay().getMetrics(metrics);
            screenWidth = metrics.widthPixels;
            screenHeight = metrics.heightPixels;
        }
        Log.d(TAG, "获取手机屏幕宽高：" + screenWidth + "×" + screenHeight);



        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) {
                Log.d(TAG, "surfaceView MeasuredWidth×MeasuredHeight:" + surfaceView.getMeasuredWidth() + "×" + surfaceView.getMeasuredHeight());
                if (camera == null) {
                    openCamera(cameraId);
                }
                startPreview();
            }

            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

            }
        });
    }

    private void initView() {
        surfaceView = findViewById(R.id.sf_camera);
        btn_back = findViewById(R.id.btn_back);
        btn_back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MameraActivity.this.finish();
            }
        });

        btn_capture = findViewById(R.id.btn_capture);
        btn_capture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (camera != null) {
                    camera.takePicture(new Camera.ShutterCallback() {
                                           @Override
                                           public void onShutter() {

                                           }
                                       }, // 回调没压缩的原始数据 raw
                            new Camera.PictureCallback() {
                                @Override
                                public void onPictureTaken(byte[] data, Camera camera) {

                                }
                            },
                            // 回调图片数据 点击拍照后相机返回的照片byte数组
                            new Camera.PictureCallback() {
                                @Override
                                public void onPictureTaken(byte[] data, Camera camera) {
                                    camera.startPreview();
                                    String photoPath;
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                                        photoPath = getExternalFilesDir(null).getAbsolutePath();
                                    } else {
                                        photoPath = Environment.getExternalStorageDirectory().getAbsolutePath();
                                    }
                                    String photoPathName = photoPath + File.separator + System.currentTimeMillis() + ".jpeg";
                                    File photoFile = new File(photoPathName);
                                    Log.d(TAG, "照片路径：" + photoFile);
                                    try {
                                        FileOutputStream fos = new FileOutputStream(photoFile);
                                        if (!photoFile.exists()) {
                                            boolean isCreated = photoFile.createNewFile();
                                            Log.d(TAG, "照片创建结果：" + isCreated);
                                        }
                                        // fos.write(data);
                                        // 旋转角度，保证保存的图片方向是对的
                                        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                                        Matrix matrix = new Matrix();
                                        matrix.setRotate(90);
                                        bitmap = Bitmap.createBitmap(bitmap, 0, 0,
                                                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                                        fos.flush();
                                        fos.close();
                                        bitmap.recycle();

                                        Intent resultIntent = new Intent();
                                        resultIntent.putExtra(EXTRA_FILE_PATH, photoPathName);
                                        setResult(Activity.RESULT_OK, resultIntent);
                                        finish();
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        Log.e(TAG, "照片保存异常");
                                    }
                                }
                            });
                }
            }
        });

        btn_flashlight = findViewById(R.id.btn_flashlight);
        btn_flashlight.setTag("OFF");
        btn_flashlight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Object tag = v.getTag();
                if (tag == null || "OFF".equals(tag)) {
                    v.setTag("ON");
                } else {
                    v.setTag("OFF");
                }
                tag = v.getTag();
                boolean turnLight = "ON".equals(tag);
                if (turnLight) {
                    btn_flashlight.setImageDrawable(getResources().getDrawable(R.drawable.ic_capture_flashlight_on));
                } else {
                    btn_flashlight.setImageDrawable(getResources().getDrawable(R.drawable.ic_capture_flashlight_off));
                }
                turnLight(turnLight);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, TAG + "#onDestroy()");
        releaseCamera();
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, TAG + "#onPause()");
        releaseCamera();
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, TAG + "#onResume()");
        if (camera == null) {
            openCamera(cameraId);
        }
        startPreview();
    }

    private void startPreview() {
        if (camera != null) {
            try {
                camera.setPreviewDisplay(surfaceHolder);
                // 设置预览角度
                setCameraDisplayOrientation(camera, cameraId);
                camera.startPreview();
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, "启动相机预览异常");
            }
        }
    }

    private List<Camera.Size> getCameraPreviewSizes(Camera.Parameters cameraParameters) {
        List<Camera.Size> cameraPreviewSize = null;
        if (cameraParameters != null) {
            cameraPreviewSize = cameraParameters.getSupportedPreviewSizes();
            if (cameraPreviewSize != null && !cameraPreviewSize.isEmpty()) {
                int cameraSizeLength = cameraPreviewSize.size();
                for (int n = 0; n < cameraSizeLength; n++) {
                    Camera.Size size = cameraPreviewSize.get(n);
                    Log.d(TAG, "系统支持的预览尺寸（宽×高）：" + size.width + "×" + size.height);
                }
            }
        }
        return cameraPreviewSize;
    }

    private List<Camera.Size> getPictureSizes(Camera.Parameters cameraParameters) {
        List<Camera.Size> pictureSizes = null;
        if (cameraParameters != null) {
            pictureSizes = cameraParameters.getSupportedPictureSizes();
            if (pictureSizes != null && !pictureSizes.isEmpty()) {
                int cameraSizeLength = pictureSizes.size();
                for (int n = 0; n < cameraSizeLength; n++) {
                    Camera.Size size = pictureSizes.get(n);
                    Log.d(TAG, "系统支持的照片尺寸（宽×高）：" + size.width + "×" + size.height);
                }
            }
        }
        return pictureSizes;
    }

    private Camera.Size getOptimalPreviewSize(Camera.Parameters cameraParameters, int w, int h) {

        List<Camera.Size> sizes = getCameraPreviewSizes(cameraParameters);
        if (sizes == null) {
            return null;
        }
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) h / w;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;
            int tempDiff = Math.abs(size.height - targetHeight);
            if (tempDiff < minDiff) {
                optimalSize = size;
                minDiff = tempDiff;
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        if (optimalSize != null) {
            Log.d(TAG, "最佳预览尺寸（宽×高）：" + optimalSize.width + "×" + optimalSize.height);
        } else {
            Log.d(TAG, "最佳预览尺寸获取为空");
        }
        return optimalSize;
    }

    private void fixScreenSize(int fitSizeHeight, int fitSizeWidth) {

        // 预览 View 的大小，比如 SurfaceView
        int viewHeight = screenHeight;
        int viewWidth = screenWidth;
        // 相机选择的预览尺寸
        int cameraHeight = fitSizeWidth;
        int cameraWidth = fitSizeHeight;
        // 计算出将相机的尺寸 => View 的尺寸需要的缩放倍数
        float ratioPreview = (float) cameraWidth / cameraHeight;
        float ratioView = (float) viewWidth / viewHeight;
        float scaleX, scaleY;
        if (ratioView < ratioPreview) {
            scaleX = ratioPreview / ratioView;
            scaleY = 1;
        } else {
            scaleX = 1;
            scaleY = ratioView / ratioPreview;
        }
        // 计算出 View 的偏移量
        float scaledWidth = viewWidth * scaleX;
        float scaledHeight = viewHeight * scaleY;
        float dx = (viewWidth - scaledWidth) / 2;
        float dy = (viewHeight - scaledHeight) / 2;

        Matrix matrix = new Matrix();
        matrix.postScale(scaleX, scaleY);
        matrix.postTranslate(dx, dy);

        float[] values = new float[9];
        matrix.getValues(values);
        surfaceView.setTranslationX(values[Matrix.MTRANS_X]);
        surfaceView.setTranslationY(values[Matrix.MTRANS_Y]);
        surfaceView.setScaleX(values[Matrix.MSCALE_X]);
        surfaceView.setScaleY(values[Matrix.MSCALE_Y]);
        surfaceView.invalidate();
    }

    /**
     * 设置预览界面尺寸
     */
    public Camera.Size getPreviewSize(Camera.Parameters cameraParameters, int width, int height) {
        // 获取系统支持预览大小
        List<Camera.Size> cameraPreviewSize = getCameraPreviewSizes(cameraParameters);
        Camera.Size biggestSize = null; // 最大分辨率
        Camera.Size fitSize = null; // 优先选屏幕分辨率
        Camera.Size targetSize = null; // 没有屏幕分辨率就取跟屏幕分辨率相近(大)的
        Camera.Size targetSiz2 = null; // 没有屏幕分辨率就取跟屏幕分辨率相近(小)的
        if (cameraPreviewSize != null) {
            int cameraSizeLength = cameraPreviewSize.size();
            // 如果是 预览窗口宽：高 ==  3：4的话
            if (Float.valueOf(width) / height == 3.0f / 4) {
                for (int n = 0; n < cameraSizeLength; n++) {
                    Camera.Size size = cameraPreviewSize.get(n);
                    if (Float.valueOf(size.width) / size.height == 4.0f / 3) {
                        // cameraParameters.setPreviewSize(size.width, size.height);
                        return size;
                    }
                }
            } else {
                // 全屏幕预览
                for (int n = 0; n < cameraSizeLength; n++) {
                    Camera.Size size = cameraPreviewSize.get(n);
                    if (biggestSize == null ||
                            (size.width >= biggestSize.width && size.height >= biggestSize.height)) {
                        biggestSize = size;
                    }

                    // 如果支持的比例都等于所获取到的宽高
                    if (size.width == height && size.height == width) {
                        fitSize = size;
                        // 如果任一宽或者高等于所支持的尺寸
                    } else if (size.width == height || size.height == width) {
                        if (targetSize == null) {
                            targetSize = size;
                            // 如果上面条件都不成立 如果任一宽高小于所支持的尺寸
                        } else if (size.width < height || size.height < width) {
                            targetSiz2 = size;
                        }
                    }
                }

                if (fitSize == null) {
                    fitSize = targetSize;
                }

                if (fitSize == null) {
                    fitSize = targetSiz2;
                }

                if (fitSize == null) {
                    fitSize = biggestSize;
                }
                // cameraParameters.setPreviewSize(fitSize.width, fitSize.height);
                // fixScreenSize(fitSize.height, fitSize.width);
            }
            if (fitSize != null) {
                Log.d(TAG, "预览尺寸（宽×高）：" + fitSize.width + "×" + fitSize.height);
            } else {
                Log.w(TAG, "获取预览尺寸为空");
            }
        }
        return fitSize;
    }

    private Camera.Size getBestPreviewSize(int width, int height) {
        Camera.Size optimalSize = null;
        List<Camera.Size> cameraSize = getCameraPreviewSizes(cameraParameters);
        for (Camera.Size size : cameraSize) {
            if (size.width <= width && size.height <= height) {
                if (optimalSize == null) {
                    optimalSize = size;
                } else {
                    int resultArea = optimalSize.width * optimalSize.height;
                    int newArea = size.width * size.height;

                    if (newArea > resultArea) {
                        optimalSize = size;
                    }
                }
            }
        }
        if (optimalSize != null) {
            Log.d(TAG, "最佳预览尺寸（宽×高）：" + optimalSize.width + "×" + optimalSize.height);
        }
        return optimalSize;
    }

    /**
     * 设置保存图片的尺寸
     */
    private void setPictureSize() {
        if (cameraParameters != null) {
            List<Camera.Size> pictureSizes = cameraParameters.getSupportedPictureSizes();
            Camera.Size biggestSize = null;
            Camera.Size fitSize = null; // 优先选预览界面的尺寸
            Camera.Size previewSize = cameraParameters.getPreviewSize(); // 获取预览界面尺寸
            Log.d(TAG, "获取预览尺寸：" + previewSize.width + "×" + previewSize.height);
            float previewSizeScale = 0;
            if (previewSize != null) {
                previewSizeScale = previewSize.width / (float) previewSize.height;
            }
            Log.d(TAG, "预览尺寸比例：" + previewSizeScale);

            if (pictureSizes != null) {
                int cameraSizeLength = pictureSizes.size();
                for (int n = 0; n < cameraSizeLength; n++) {
                    Camera.Size size = pictureSizes.get(n);
                    Log.d(TAG, "系统支持的图片尺寸（宽×高）：" + size.width + "×" + size.height);
                    if (biggestSize == null) {
                        biggestSize = size;
                    } else if (size.width >= biggestSize.width && size.height >= biggestSize.height) {
                        biggestSize = size;
                    }

                    // 选出与预览界面等比的最高分辨率
                    if (previewSizeScale > 0
                            && size.width >= previewSize.width && size.height >= previewSize.height) {
                        float sizeScale = size.width / (float) size.height;
                        if (sizeScale == previewSizeScale) {
                            if (fitSize == null) {
                                fitSize = size;
                            } else if (size.width >= fitSize.width && size.height >= fitSize.height) {
                                fitSize = size;
                            }
                        }
                    }
                }

                // 如果没有选出fitSize, 那么最大的size就是fitSize
                if (fitSize == null) {
                    fitSize = biggestSize;
                }
                cameraParameters.setPictureSize(fitSize.width, fitSize.height);
            }
            if (fitSize != null) {
                Log.d(TAG, "照片尺寸（宽×高）：" + fitSize.width + "×" + fitSize.height);
            } else {
                Log.w(TAG, "设置照片尺寸为空");
            }
        }
    }

    private void adjustPreviewSize() {
        if (cameraParameters != null) {
            List<Camera.Size> cameraSize = getCameraPreviewSizes(cameraParameters);
            if (cameraSize == null || cameraSize.isEmpty()) {
                Log.d(TAG, "相机预览尺寸为空");
                return;
            }

            int w = screenWidth;
            int h = screenHeight;

            final double ASPECT_TOLERANCE = 0.1;
            double targetRatio = (double) w / h;

            Camera.Size optimalSize = null;
            double minDiff = Double.MAX_VALUE;

            int targetHeight = h;
            for (Camera.Size size : cameraSize) {
                double ratio = (double) size.width / size.height;
                if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                    continue;
                ;
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }

            if (optimalSize == null) {
                minDiff = Double.MAX_VALUE;
                for (Camera.Size size : cameraSize) {
                    if (Math.abs(size.height - targetHeight) < minDiff) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
            }
            Log.d(TAG, "预览尺寸（宽×高）：" + optimalSize.width + "×" + optimalSize.height);
            cameraParameters.setPreviewSize(optimalSize.width, optimalSize.height);
            fixScreenSize(optimalSize.width, optimalSize.height);
        }
    }

    private void setCameraDisplayOrientation(Camera camera, int cameraId) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, cameraInfo);

        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }

        int result;
        //计算图像所要旋转的角度
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (cameraInfo.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (cameraInfo.orientation - degrees + 360) % 360;
        }
        //调整预览图像旋转角度
        camera.setDisplayOrientation(result);
    }

    public void releaseCamera() {
        if (camera != null) {
            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    private boolean openCamera(int cameraId) {
        boolean cameraSupport = isCameraSupport(cameraId);
        if (cameraSupport) {
            try {
                camera = Camera.open(cameraId);
                initCameraParameters(camera);
                if (camera != null) {
                    camera.setPreviewCallback(new Camera.PreviewCallback() {
                        @Override
                        public void onPreviewFrame(byte[] bytes, Camera camera) {

                        }
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, "打开相机失败，cameraId=" + cameraId);
            }
        }
        return cameraSupport;
    }

    private void initCameraParameters(Camera camera) {
        try {
            cameraParameters = camera.getParameters();
            cameraParameters.setPreviewFormat(ImageFormat.NV21);

            // adjustPreviewSize();

            // setPreviewSize(screenWidth, screenHeight);

            // List<Camera.Size> previewSizes = getCameraPreviewSizes(cameraParameters);
            //Camera.Size previewSize = getOptimalPreviewSize(previewSizes, screenWidth, screenHeight);
            //cameraParameters.setPreviewSize(previewSize.width, previewSize.height);

            //setPictureSize();

            // Camera.Size optimalSize = getBestPreviewSize(screenWidth,screenHeight);
            // Camera.Size optimalSize = getOptimalPreviewSize(cameraParameters, screenWidth, screenHeight);
            Camera.Size optimalSize = getPreviewSize(cameraParameters, screenWidth, screenHeight);
            cameraParameters.setPreviewSize(optimalSize.width, optimalSize.height);
            cameraParameters.setPictureSize(optimalSize.width, optimalSize.height);

            // 自动对焦模式设置
            // 连续自动对焦
            if (isSupportFocus(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            }
            // 单次自动对焦
            else if (isSupportFocus(Camera.Parameters.FOCUS_MODE_AUTO)) {
                cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            }
            camera.setParameters(cameraParameters);
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "初始化相机参数异常");
        }
    }

    private boolean isSupportFocus(String focusMode) {
        boolean isSupport = false;
        if (cameraParameters != null) {
            List<String> focusModeList = cameraParameters.getSupportedFocusModes();
            for (String mode : focusModeList) {
                if (mode.equals(focusMode)) {
                    isSupport = true;
                }
            }
        }
        return isSupport;
    }

    private boolean isCameraSupport(int cameraId) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraId == cameraInfo.facing) {
                return true;
            }
        }
        return false;
    }

    public void turnLight(boolean turnSwitch) {
        if (camera != null) {
            Camera.Parameters cameraParameters = camera.getParameters();
            if (cameraParameters != null) {
                cameraParameters.setFlashMode(turnSwitch ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF);
                camera.setParameters(cameraParameters);
            }
        }
    }
}
